package DB;

import java.sql.Connection;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class UserManager extends DB {

    public UserManager(String dbName, String userName, String password) {
        super(dbName, userName, password);
    }

    public UserManager(Connection c) {
        conn = c;
    }

    public boolean isValidPassword(String pw) {
        return pw.length() > 3;
    }

    public boolean isValidUserName(String username) {
        return username.length() > 3 && ((username.charAt(0) >= 'a' && username.charAt(0) <= 'z') || (username.charAt(0) >= 'A' && username.charAt(0) <= 'Z'));
    }

    public boolean isValidFullName(String fullName) {
        return fullName.matches("[a-zA-Zé]+\\s[a-zA-Zé]+$");
    }

    public boolean isValidEmail(String email) {
        return email.matches("[A-Za-z0-9\\.\\-_]+@[A-Za-z0-9\\.\\-_]+\\.[A-Za-z0-9\\.\\-_]+$");
    }

    public boolean fullNameExists(String user) {
        if (isConnected() && !(user.isEmpty())) {
            try {
                PreparedStatement pstmt = conn.prepareStatement("SELECT * " + " FROM Users WHERE fullName= ?");
                pstmt.setString(1, user);
                ResultSet rs = pstmt.executeQuery();
                if (rs.next()) {
                    return true;
                } else {
                    return false;
                }
            } catch (SQLException ex) {
                return true;
            }
        } else {
            return true;
        }
    }

    public String getPassword(String user) {
        if (isConnected() && !(user.isEmpty())) {
            try {
                PreparedStatement pstmt = conn.prepareStatement("SELECT password FROM Users WHERE username= ?");
                pstmt.setString(1, user);
                ResultSet rs = pstmt.executeQuery();
                if (rs.next()) {
                    return rs.getString(1);
                } else {
                    return null;
                }
            } catch (SQLException ex) {
                return null;
            }
        } else {
            return null;
        }
    }

    public String getRegistrationDate(String user) {
        if (isConnected() && usernameExists(user)) {
            try {
                PreparedStatement pstmt = conn.prepareStatement("SELECT registrationDate  FROM Users WHERE username= ?");
                pstmt.setString(1, user);
                ResultSet rs = pstmt.executeQuery();
                if (rs.next()) {
                    String result = rs.getTimestamp(1).toString();
                    return result.substring(0, result.indexOf(' '));
                } else {
                    return "";
                }
            } catch (SQLException ex) {
                return "";
            }
        } else {
            return "";
        }
    }

    public boolean changePassword(String user, String passWord) {
        if (isConnected() && usernameExists(user) && isValidPassword(passWord)) {
            try {
                PreparedStatement pstmt = conn.prepareStatement("UPDATE Users SET password= ? WHERE username= ?");
                pstmt.setString(1, hashPassword(passWord));
                pstmt.setString(2, user);
                pstmt.executeUpdate();
                return true;
            } catch (SQLException ex) {
                return false;
            }
        } else {
            return false;
        }
    }

    public String getFullName(String user) {
        if (isConnected() && usernameExists(user)) {
            try {
                PreparedStatement pstmt = conn.prepareStatement("SELECT fullName FROM Users WHERE username= ?");
                pstmt.setString(1, user);
                ResultSet rs = pstmt.executeQuery();
                if (rs.next()) {
                    return rs.getString(1);
                } else {
                    return "";
                }
            } catch (SQLException ex) {
                return null;
            }
        } else {
            return null;
        }
    }

    public boolean changeFullName(String user, String full) {
        if (isConnected() && usernameExists(user) && isValidFullName(full)) {
            try {
                PreparedStatement pstmt = conn.prepareStatement("UPDATE Users SET fullName= ? WHERE username= ?");
                pstmt.setString(1, full);
                pstmt.setString(2, user);
                pstmt.executeUpdate();
                return true;
            } catch (SQLException ex) {
                return false;
            }
        } else {
            return false;
        }
    }

    public String getEmail(String user) {
        if (isConnected() && usernameExists(user)) {
            try {
                PreparedStatement pstmt = conn.prepareStatement("SELECT email FROM Users WHERE username= ?");
                pstmt.setString(1, user);
                ResultSet rs = pstmt.executeQuery();
                if (rs.next()) {
                    return rs.getString(1);
                } else {
                    return "";
                }
            } catch (SQLException ex) {
                return "";
            }
        } else {
            return "";
        }
    }

    public boolean changeEmail(String user, String email) {
        if (isConnected() && usernameExists(user) && isValidEmail(email)) {
            try {
                PreparedStatement pstmt = conn.prepareStatement("UPDATE Users SET email= ? WHERE username= ?");
                pstmt.setString(1, email);
                pstmt.setString(2, user);
                pstmt.executeUpdate();
                return true;
            } catch (SQLException ex) {
                return false;
            }
        } else {
            return false;
        }
    }

    public boolean showInfo(String user) {
        if (isConnected() && usernameExists(user)) {
            try {
                PreparedStatement pstmt = conn.prepareStatement("SELECT showInfo FROM Users WHERE username= ?");
                pstmt.setString(1, user);
                ResultSet rs = pstmt.executeQuery();
                if (rs.next()) {
                    return (rs.getInt(1) == 0) ? false : true;
                } else {
                    return false;
                }
            } catch (SQLException ex) {
                return false;
            }
        } else {
            return false;
        }
    }

    public boolean changeShowInfo(String user, boolean flag) {
        if (isConnected() && usernameExists(user)) {
            try {
                PreparedStatement pstmt = conn.prepareStatement("UPDATE Users SET showInfo= ? WHERE username= ?");
                pstmt.setString(2, user);
                pstmt.setByte(1, flag ? (byte) 1 : (byte) 0);
                pstmt.executeUpdate();
                return true;
            } catch (SQLException ex) {
                return false;
            }
        } else {
            return false;
        }
    }

    public boolean addUser(String user, String fullName, String email, String password) {
        if (isConnected() && !usernameExists(user) && isValidEmail(email) && isValidFullName(fullName) && isValidPassword(password) && isValidUserName(user)) {
            try {
                /*
                // Send the confirmation mail
                InternetAddress sender;
                InternetAddress receiver;
                try {
                sender = new InternetAddress("noreply@helloworld.com");
                receiver = new InternetAddress(email);
                } catch (javax.mail.internet.AddressException e) {
                System.out.println("AddressException " + e.getMessage());
                return false;
                }
                
                Properties props = new Properties();
                props.put("mail.smtp.host", "localhost);
                props.put("mail.smtp.auth", "false");
                props.setProperty("mail.transport.protocol", "smtp");
                
                Session session = Session.getDefaultInstance(props, null);
                
                //bericht aanmaken
                Message msg = new MimeMessage(session);
                
                try {
                msg.setFrom(sender);
                msg.setRecipient(Message.RecipientType.TO, receiver);
                msg.setSubject("Confirmation for the Hello World website");
                msg.setContent(message, "text/plain");
                Transport.send(msg);
                
                } catch (javax.mail.MessagingException e) {
                System.out.println("MessagingException " + e.getMessage());
                return false;
                }*/

                // If the mail could be sent, we add the user
                PreparedStatement pstmt = conn.prepareStatement("INSERT INTO Users (username, password, fullName, email, showInfo) VALUES ( ?, ?, ?, ?, 0)");
                pstmt.setString(1, user);
                pstmt.setString(2, hashPassword(password));
                pstmt.setString(3, fullName);
                pstmt.setString(4, email);
                //pstmt.setBoolean(5, false);
                // Confirmed is automatically set to false by the database
                pstmt.executeUpdate();

                return true;

            } catch (SQLException ex) {
                System.out.println("SQL exception on add user: " + ex.getMessage());
                return false;
            }
        } else {
            return false;
        }
    }

    public boolean deleteUser(String user) {
        if (isConnected() && usernameExists(user)) {
            try {
                PreparedStatement pstmt = conn.prepareStatement("DELETE FROM Users WHERE username= ?");
                pstmt.setString(1, user);
                pstmt.executeUpdate();
                return true;
            } catch (SQLException ex) {
                return false;
            }
        }
        return false;
    }

    public String[] getUsersLike(String query) {
        if (isConnected()) {
            try {
                PreparedStatement pstmt = conn.prepareStatement("SELECT username FROM Users WHERE username LIKE ? LIMIT 10");
                pstmt.setString(1, query + "%");
                ResultSet rs = pstmt.executeQuery();
                String[] result = null;
                int currentRow = 0;

                if (rs.next()) {
                    rs.previous();
                    result = new String[1];

                    while (rs.next()) {
                        result[currentRow] = rs.getString(1);
                        currentRow++;
                        if (rs.next()) {
                            rs.previous();
                            String[] temp = new String[currentRow + 1];
                            System.arraycopy(result, 0, temp, 0, result.length);
                            result = temp;
                        }
                    }
                }

                if (result == null) // Make sure it always returns an array
                {
                    result = new String[0];
                }
                return result;
            } catch (SQLException ex) {
                return new String[0];
            }
        } else {
            return new String[0];
        }
    }

    public static String hashPassword(String password) {
        String hashword = null;
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(password.getBytes());
            BigInteger hash = new BigInteger(1, md5.digest());
            hashword = hash.toString(16);

        } catch (NoSuchAlgorithmException nsae) {
        }
        return pad(hashword, 32, '0');
    }

    public static String pad(String s, int length, char pad) {
        StringBuffer buffer = new StringBuffer(s);
        while (buffer.length() < length) {
            buffer.insert(0, pad);
        }
        return buffer.toString();
    }
}
